'''
Author:thinktanker thinktanker@163.com
Date:2024-01-26 11:43:56
LastEditors: duliang thinktanker@163.com
LastEditTime: 2025-10-07 17:05:11
FilePath:
Description:
'''
# import asyncio
import httpx
import aiofiles
from fastapi import FastAPI, Form, Body, File, Request, UploadFile
from fastapi.responses import FileResponse, PlainTextResponse, Response
# , HTMLResponse, StreamingResponse
# rom fastapi.responses import StreamingResponse
from fastapi.middleware.cors import CORSMiddleware
from starlette.responses import JSONResponse
from fastapi.templating import Jinja2Templates
from fastapi.requests import Request
from fastapi.staticfiles import StaticFiles
import time
import sqlite3
from threading import Thread
# from multiprocessing import Process
import os
from datetime import timezone
# 三方库
from pypinyin import lazy_pinyin
import psutil
# 自定义函数
from getipaddress import *
from getgkdb import *
from getsq import *
from ocr import *
from fapiao import *
import diancan
import lyjswater
import wechatsubscribe
# from cpu_mem_watch import check_cpu_memory
import xxtk

os.system('title 大服务器')
print("启动服务器")
# 获取当前进程
process = psutil.Process(os.getpid())
# app = Flask(__name__)
app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    # 允许跨域的源列表，例如 ["http://www.example.org"] 等等，["*"] 表示允许任何源
    allow_origins=["*"],
    # 跨域请求是否支持 cookie，默认是 False，如果为 True，allow_origins 必须为具体的源，不可以是 ["*"]
    allow_credentials=False,
    # 允许跨域请求的 HTTP 方法列表，默认是 ["GET"]
    allow_methods=["*"],
    # 允许跨域请求的 HTTP 请求头列表，默认是 []，可以使用 ["*"] 表示允许所有的请求头
    # 当然 Accept、Accept-Language、Content-Language 以及 Content-Type 总之被允许的
    allow_headers=["*"],
    # 可以被浏览器访问的响应头, 默认是 []，一般很少指定
    # expose_headers=["*"]
    # 设定浏览器缓存 CORS 响应的最长时间，单位是秒。默认为 600，一般也很少指定
    # max_age=1000
)
# 配置模板目录
templates = Jinja2Templates(directory="templates")
# 挂载静态文件目录
app.mount("/static", StaticFiles(directory="static"), name="static")
flag_time = 0
flag_time0 = 0
flag_time1 = 0
flag_time10 = 0
time_get_new = 10
# 判断中控接受是否超时，客户端是否在线
zhongkong_time = time.time()
zhongkong2_time = time.time()
# 判断是否有新的消息
newcheck = 0
# 是否mqtt发布
publish_flag = False
# 发布名称，作为重要标记
publish_name = ''
publish_type = None
# IP请求记录字典，用于频率限制
ip_requests = {}
# 频率限制配置：每60秒内最多允许100次请求
RATE_LIMIT = 200
TIME_WINDOW = 60


def saveLog(newlog, newtime, insert=True):
    '''
    保存log信息
    '''
    newlog = newlog.replace('机13', '机Ia').replace('1a', 'Ia').replace(
        'QQ', 'Q0').replace('”', '')
    conn = sqlite3.connect('./data/hisdata.db')
    cur = conn.cursor()
    if insert:
        sql = f'''INSERT INTO "history" ("xin", "shijian") VALUES ('{newlog}', {int(newtime)})'''
    else:
        sql = f'''UPDATE "history" SET "zhuijia"='{newlog}' WHERE ("shijian"={int(newtime)});'''
    cur.execute(sql)
    conn.commit()
    cur.close()
    conn.close()


# # 列表中存储被禁止的 IP 地址
# banned_ips = ['192.168.1.1', '::1']  # 示例 IP，根据需要替换或添加
# 列表中存储被允许的 IP 地址
# allowed_ips = [
#     '192.168.3.163', '223.68.11.42', '192.168.15.101', '218.93.240.126'
# ]  # 示例 IP，根据需要替换或添加


def save_ip(ip, ban):
    try:
        conn = sqlite3.connect('./data/users.db')
        cur = conn.cursor()
        sql = f'''SELECT count FROM "ip" WHERE "ip"="{ip}"'''
        rs = conn.execute(sql)
        rf = rs.fetchone()
        # print(rf)
        if rf:
            count = rf[0]
            sql = f'''UPDATE "ip" SET "count"={count+1},"last_time"={int(time.time())},"ban"={ban} WHERE "ip"="{ip}"'''
            cur.execute(sql)
            conn.commit()
        else:
            ip_address = get_ip_address([ip])
            if ip_address:
                ip_address = ip_address[0]
            sql = f'''INSERT INTO "ip" ("ip", "count","time","last_time","ban","address") VALUES ("{ip}", 1,{int(time.time())},{int(time.time())},{ban},"{ip_address}")'''
            cur.execute(sql)
            conn.commit()
    except Exception as e:
        print(e)
    finally:
        conn.close()


@app.middleware("https")
async def check_ip(request: Request, call_next):
    try:
        # 获取X-Forwarded-For头信息
        x_forwarded_for = request.headers.get("X-Forwarded-For")
        # print(x_forwarded_for)

        # 处理X-Forwarded-For可能的格式
        if x_forwarded_for:
            # 通常取第一个IP作为客户端IP，注意可能存在伪造风险
            client_ip = x_forwarded_for.split(",")[0]
        else:
            # 如果没有X-Forwarded-For头，则使用remote_addr（这通常是代理服务器的IP）
            client_ip = request.client.host

        print(
            f"\033[0;31;42m{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))} Client IP: {client_ip}\033[0m"
        )

        # 检查并限制IP访问频率
        current_time = time.time()

        # 清理过期的请求记录
        if client_ip in ip_requests:
            ip_requests[client_ip] = [
                req_time for req_time in ip_requests[client_ip]
                if current_time - req_time < TIME_WINDOW
            ]
        else:
            ip_requests[client_ip] = []

        # 检查是否超过频率限制
        if len(ip_requests[client_ip]) >= RATE_LIMIT:
            # 修复：使用正确的Response类
            return Response(content="Too Many Requests", status_code=429)

        # 记录当前请求
        ip_requests[client_ip].append(current_time)

        Thread(target=save_ip, args=(client_ip, 1)).start()
        '''
        屏蔽ip
        '''
        with open('./config/config.json', "r", encoding='utf8') as f:
            forbbidden_ips = json.load(f)['forbbidden_ips']
        if client_ip in forbbidden_ips:
            return JSONResponse(
                status_code=403,
                content={"detail": f"Access from IP {client_ip} is not allowed."},
            )
            # raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
            #                 detail="Access Forbidden")
        response = await call_next(request)
        return response
    except Exception as e:
        # 捕获所有异常并返回适当的错误响应
        print(f"Middleware error: {e}")
        # 修复：使用正确的Response类
        return Response(content="Internal server error", status_code=500)
    # client_ip = request.client.host
    # # print("收到来自：", client_ip)
    # # save_ip(client_ip, 0)
    # Thread(target=save_ip, args=(client_ip, 1)).start()
    # with open('./config/config.json', "r") as f:
    #     ALLOWED_IPS = json.load(f)['allowed_ips']
    # if client_ip not in ALLOWED_IPS:
    #     return JSONResponse(
    #         status_code=403,
    #         content={"detail": f"Access from IP {client_ip} is not allowed."},
    #     )
    #     # raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
    #     #                     detail="Access Forbidden")
    # response = await call_next(request)
    # return response


@app.get("/zhongkong")
async def zhongkong_get(t: str = None):
    if t:
        if t == "wankeyun":
            async with aiofiles.open("./config/config.json",
                                     encoding="utf8") as f:
                j = json.loads(await f.read())
                screenName_list = j["wankeyun"]
                return {"screenName_list": screenName_list}
    return PlainTextResponse("ip")


@app.post("/zhongkong")
async def zhongkong_post(request: Request):
    global zhongkong_time
    recv_time = time.time()
    # print('zhongkong_time', recv_time)
    zhongkong_time = recv_time
    recv_data = await request.body()
    # recv_data = recv_data.decode("utf8", "ignore")
    # print(f"\033[32;4m字节数:{len(recv_data)}\033[0m")
    # if len(recv_data) > 500:
    #     print(
    #         f"\033[32m{ recv_data[:100]}********************{ recv_data[-10:]}\033[0m"
    #     )
    # else:
    #     print(f"\033[32m{ recv_data}\033[0m")
    print(f"\033[32;4m字节数:{len(recv_data)}\033[0m")
    try:
        th2 = Thread(target=judge, args=(recv_time, recv_data, 1), daemon=True)
        th2.start()
        return PlainTextResponse(f"{len(recv_data)}")
    except Exception as e:
        return PlainTextResponse(str(e), status_code=500)


@app.get("/zhongkong2")
async def zhongkong2_get(request: Request):
    return PlainTextResponse(request.client.host)


@app.post("/zhongkong2")
async def zhongkong2_post(request: Request):
    global zhongkong2_time
    recv_time = time.time()
    # print('zhongkong2_time', recv_time)
    zhongkong2_time = recv_time
    recv_data = await request.body()
    # recv_data = recv_data.decode("utf8", "ignore")
    print(f"\033[32;4m字节数:{len(recv_data)}\033[0m")
    print(f"\033[32m{ recv_data}\033[0m")
    try:
        th2 = Thread(target=judge, args=(recv_time, recv_data, 2), daemon=True)
        th2.start()
        return PlainTextResponse(f"{len(recv_data)}")
    except Exception as e:
        return PlainTextResponse(str(e), status_code=500)


@app.get("/sim")
async def sim_get(request: Request):
    return PlainTextResponse(request.client.host)


@app.post("/sim")
async def sim_post(request: Request):
    global zhongkong_time
    recv_time = time.time()
    print('zhongkong_time', recv_time)
    zhongkong_time = recv_time
    recv_data = await request.body()
    # recv_data = recv_data.decode("utf8", "ignore")
    print(f"\033[32;4m字节数:{len(recv_data)}\033[0m")
    print(f"\033[32m{ recv_data}\033[0m")
    try:
        th2 = Thread(target=judge, args=(recv_time, recv_data, 1), daemon=True)
        th2.start()
        return PlainTextResponse(f"{len(recv_data)}")
    except Exception as e:
        return PlainTextResponse(str(e), status_code=500)


# @app.route('/ip', methods=['GET'])
# def ip():
#     if request.method == 'GET':
#         return request.remote_addr


@app.get("/ip")
async def ip(request: Request):
    return request.client.host


@app.post('/gongkong')
async def gongkong(data: dict):
    starttime = round(time.time(), 2)
    if not data:
        return {"error": "No JSON data received"}, 400
    gcnum = data.get('gcnum')
    print(f"{gcnum}工控访问")
    openid = data.get('openid')
    th = Thread(target=updateUser, args=(openid, ))
    th.daemon = True
    th.start()
    if gcnum is None:
        return {"error": "Missing 'gcnum' in JSON data"}, 400
    async with aiofiles.open("./config/config.json", "r",
                             encoding="utf8") as f:
        config = json.loads(await f.read())
    # 预测plus_time分钟后，对比past_time小时
    plus_time = int(config['plus_time']) * 60
    past_time = int(config['past_time']) * 60 * 60
    result = {"error": "wrong gcnum in JSON data"}
    if int(gcnum) == 0:
        respdata = getgq_1zhan_db(plus_time=plus_time, past_time=past_time),
        result = {
            "respdata": respdata[0][0],
            "warn": respdata[0][1]
            # "respdata": getgq_1zhan(plus_time=plus_time, past_time=past_time)
        }
    elif int(gcnum) == 1:
        result = {
            "respdata": getgq_2zhan(plus_time=plus_time, past_time=past_time)
        }
    # else:
    #     return {"error": "wrong gcnum in JSON data"}, 400
    print(f"{gcnum}结束", round(time.time() - starttime, 2))
    return result


@app.get('/wdimg')
async def wdimg(gcnum: str, t: str):
    '''
    获取温度图片
    '''
    global flag_time
    gctime = t
    if (gcnum == "0" or gcnum == "1") and gctime:
        gctime = int(gctime)
        response = FileResponse(f'./image/#{int(gcnum)+1}zwd_th.png',
                                media_type='image/png')
        return response
    else:
        return "error", 400


@app.get('/indeximg')
async def indeximg(src: str):
    '''
    获取首页简单信息图片
    '''
    if src:
        if src == "1" or src == "2":
            response = FileResponse(f'./image/{src}_station_main_image.png',
                                    media_type='image/png')
            return response
        else:
            response = FileResponse(f'./image/temp.png',
                                    media_type='image/png')
            return response
    else:
        return "error"


@app.get('/com')
async def com(gcnum: str):
    '''
    获取通信状态
    '''
    if gcnum:
        if gcnum == '1' or gcnum == '2':
            response = FileResponse(f'./image/{gcnum}_zhan_status.png',
                                    media_type='image/png')
            return response
        else:
            response = FileResponse(f'./image/com_lost.png',
                                    media_type='image/png')
            return response
    else:
        return PlainTextResponse('error'), 400


@app.get('/qs')
async def qs(gcname: str):
    if gcname:
        qs_png_path = getqs(gcname)
        return FileResponse(qs_png_path, media_type="image/png")
    else:
        return PlainTextResponse('error'), 400


@app.post('/detail')
async def detail(data: dict = Body(...)):
    '''
    获取数据库内对应id的详细信息
    '''
    if data:
        try:
            # 数据库的对应id，hisdata hisdata2
            dataset_id = data.get('id')
            # 数据库内对应的name,1,2,3,4,35kv,zb等
            gcname = data.get('n')
            gcname = gcname.split("Δ")[0]
            # 数据库内列名
            parameter = data.get('p')
            result = get_detail_from_db(station=dataset_id,
                                        n=gcname,
                                        p=parameter)
            return {"respdata": result}
        except Exception as e:
            print(e)
            return PlainTextResponse('error'), 400
    else:
        return PlainTextResponse('error'), 400


@app.post('/login')
async def login(data: dict = Body(...)):
    if not data:
        return {"error": "No JSON data received"}, 400
    code = data.get('code')
    # user_name = data.get('userName')
    if not code:
        return {"error": "Missing 'code' in JSON data"}, 400
    response_data = {"received_code": code}
    print(response_data)
    # if not user_name:
    #     user_name = '未知用户'
    user_info = code2session(code)
    if user_info:
        print(f"User OpenID: {user_info}")
    else:
        print("Failed to get user info.")
    return user_info


@app.get('/login')
async def login_get(n: str):
    '''
    通过openid获取用户权限
    '''
    if n:
        async with aiofiles.open('./config/setting.json', 'r',
                                 encoding='utf8') as f:
            settings = json.loads(await f.read())
            version = settings['version']
            mainpagecount = settings['mainpagecount']
        return getAllowedByopenid(n), version, mainpagecount
    return "error"


@app.get('/holidays')
async def holidays_get():
    '''
    获取节假日
    '''
    try:
        async with aiofiles.open('./config/holidays.json',
                                 'r',
                                 encoding='utf8') as f:
            holidays = json.loads(await f.read())
        return {"holidays": holidays}
    except Exception as e:
        print(f"Error loading holidays: {e}")
        return {"error": "Failed to load holidays"}, 500


@app.get('/nodes')
async def nodes_get(t: str):
    '''
    获取nodes内容
    '''
    nodes = []
    if t:
        # if type == 'all':
        try:
            async with aiofiles.open('./config/nodes.json',
                                     'r',
                                     encoding='utf8') as f:
                nodes = json.loads(await f.read())
            if nodes:
                nodes = nodes[int(t)]
        except Exception as e:
            print(f"Error loading nodes: {e}")
            # return {"error": "Failed to load nodes"}, 500
    # elif type == 'mqtt':
    return {"nodes": nodes}


@app.post('/nodes')
async def nodes_post(data: dict = Body(...)):
    '''
    
    '''
    if data:
        if data["allowed"] and data["nodeIndex"]:
            print(data["allowed"], data["nodeIndex"])
            return {
                "respdata":
                str(lyjswater.getnodesjsonByid(int(data["nodeIndex"])))
            }
    return {"respdata": "error"}, 400


@app.post('/getUserInfo')
async def getUserInfo(data: dict = Body(...)):
    # code = request.json.get('code')
    if data:
        code = data.get('code')
        encrypted_data = data.get('encryptedData')
        iv = data.get('iv')
        if not all([code, encrypted_data, iv]):
            return {"error": "缺少必要参数"}, 400
        # 假设你已经有方法获取openid和session_key，这里简化处理
        # 应该从前端传递的code再次调用get_openid_session_key来获取，这里直接使用假设值
        session_key = '+sszKAVsA7th0LlLJeoUOg=='

        # 解密用户信息
        user_info = decrypt_user_info(session_key, encrypted_data, iv)
        if user_info is None:
            return {"error": "解密失败"}, 500

        # 根据需求处理user_info，比如保存到数据库
        print(user_info)
        return user_info


@app.post('/admin')
async def admin(data: dict = Body(...)):
    '''
    test页面测试的post获得 orderID
    '''
    if not data:
        return {"error": "No JSON data received"}, 400
    orderID = data.get('id')
    value = data.get('value')
    print(orderID, value)
    # orderID 为纯数字时对应的时小程序管理员界面顶部导航index
    if orderID == 0:
        with open('./config/config.json', 'r', encoding="utf8") as f:
            config_data = json.load(f)
            allowed_ids = config_data['allowed_ids']
            allowed_ips1 = config_data['allowed_ips']
        with open(r'D:\myGitee\dul-text-recognition\allowed_ips.json',
                  'r') as f:
            config_data = json.load(f)
            allowed_ips2 = config_data['allowed_ips']
        return {"ips1": allowed_ips1, 'ips2': allowed_ips2, 'ids': allowed_ids}
    elif orderID == 1:
        conn = sqlite3.connect('./data/users.db')
        sqltxt = f"SELECT id,ip,address,time,last_time,count,ban FROM ip order by last_time desc limit 50"
        rs = conn.execute(sqltxt)
        result = rs.fetchall()
        conn.close()
        return {"visitors": result}
        # return jsonify({"error": "orderID is 1"}), 400
    elif orderID == 2:
        conn = sqlite3.connect('./data/users.db')
        sqltxt = f"SELECT id,username,count,lasttime,allowed,time,template_id,version FROM users order by lasttime desc"
        rs = conn.execute(sqltxt)
        result = rs.fetchall()
        conn.close()
        if result:
            result = list(result)
            for index, r in enumerate(result):
                result[index] = list(result[index])
                temp_list = result[index][-2]
                if temp_list:
                    temp_list = eval(temp_list)
                    for j, temp_id in enumerate(temp_list):
                        temp_list[j] = wechatsubscribe.get_template_name_by_id(
                            temp_id)
                    result[index][-2] = temp_list
            # result[index][-1] = temp_list
        return {"users": result}
    elif orderID == 3:
        session = requests.Session()
        headers = {
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
        }
        resp = session.post(url='http://localhost:18083/api/v5/login',
                            headers=headers,
                            json={
                                "username": "admin",
                                "password": "821101cCW@"
                            })
        # print(resp.json())
        token = resp.json()['token']
        headers['Authorization'] = f'Bearer {token}'
        resp = session.get(
            url=
            'http://localhost:18083/api/v5/clients?conn_state=connected&limit=20&page=1&fields=clientid,username,connected,ip_address,port,keepalive,clean_start,expiry_interval,connected_at',
            headers=headers,
        )
        resp_json = resp.json()
        clients_list = []
        for client in resp_json['data']:
            # client['connected_at']
            time_str = client['connected_at']
            # print(time_str)
            dt_obj = datetime.fromisoformat(time_str.replace("Z", "+00:00"))
            timestamp = dt_obj.replace(tzinfo=timezone.utc).timestamp()
            connected_at = time.strftime("%Y-%m-%d %H:%M:%S",
                                         time.localtime(timestamp))
            clients_list.append([client['clientid'], connected_at])
            # print(client['clientid'])
            # print(client['connected_at'])
            # print(client['connected'])

        return {"mqttClients": clients_list}
    elif orderID == 4:
        cpu_usage = ''
        memory_usage = ''
        async with aiofiles.open('./data/cpu_mem_data/cpu_usage.txt',
                                 'r',
                                 encoding='utf8') as f:
            cpu_usage = await f.read()
        async with aiofiles.open('./data/cpu_mem_data/memory_usage.txt',
                                 'r',
                                 encoding='utf8') as f:
            memory_usage = await f.read()

        return {"respdat": (cpu_usage, memory_usage)}
    elif orderID == 5:
        return {"error": f"未开发{orderID}"}, 400
    # elif orderID == 100:
    #     '''获取电池电量'''
    #     battery, charging = get_battery()
    #     return {"battery": battery, "charging": charging}
    # 导航外其他的查询等
    else:
        # 包含 _ 为ip
        if "_" in str(orderID):
            '''
            修改IP的
            '''
            order_list = str(orderID).split("_")
            if len(order_list) > 2:
                old_value = order_list[0]
                order_flag = int(order_list[1])
                json_path = int(order_list[2])
                if json_path == 1:
                    json_path = r'./config/config.json'
                elif json_path == 2:
                    json_path = r'D:\myGitee\dul-text-recognition\allowed_ips.json'
                if order_flag == 1:
                    '''
                    delete,删除IP
                    '''
                    with open(json_path, 'r', encoding='utf-8') as f:
                        config_data = json.load(f)
                        allowed_ips = config_data["allowed_ips"]  # 读取JSON文件
                        allowed_ids = config_data["allowed_ids"]  # 读取JSON文件
                        # print(allowed_ips)
                        if old_value in allowed_ips:
                            allowed_ips.remove(old_value)
                            config_data["allowed_ips"] = allowed_ips
                        elif old_value in allowed_ids:
                            allowed_ids.remove(old_value)
                            config_data["allowed_ids"] = allowed_ids
                        # 输出修改后的JSON文件
                        # print(data)
                        with open(json_path, 'w', encoding='utf-8') as f:
                            json.dump(config_data,
                                      f,
                                      ensure_ascii=False,
                                      indent=4)
                    return {"done": "deleted"}
            if value:
                new_value = value
                if order_flag == 0:
                    '''
                    update,更新IP
                    '''
                    with open(json_path, 'r', encoding='utf-8') as f:
                        config_data = json.load(f)
                        allowed_ips = config_data["allowed_ips"]  # 读取JSON文件
                        allowed_ids = config_data["allowed_ids"]  # 读取JSON文件
                        # print(allowed_ips)
                        if old_value in allowed_ips:
                            allowed_ips.remove(old_value)
                            allowed_ips.append(new_value)
                            config_data["allowed_ips"] = allowed_ips
                            config_data[
                                "allowed_ips"] = allowed_ips  # 修改JSON文件
                        else:
                            for allowed_id in allowed_ids:
                                if old_value == allowed_id['id']:
                                    allowed_ids.remove(allowed_id)
                                    config_data[
                                        "allowed_ids"] = allowed_id  # 修改JSON文件
                        # 输出修改后的JSON文件
                        # print(data)
                        with open(json_path, 'w', encoding='utf-8') as f:
                            json.dump(config_data,
                                      f,
                                      ensure_ascii=False,
                                      indent=4)
                        return {"done": "updated"}

                elif order_flag == 2:
                    '''
                    add,增加IP
                    '''
                    with open(json_path, 'r', encoding='utf-8') as f:
                        config_data = json.load(f)
                        allowed_ips = config_data["allowed_ips"]  # 读取JSON文件
                        # print(allowed_ips)
                        allowed_ips.append(new_value)
                        config_data["allowed_ips"] = allowed_ips  # 修改JSON文件
                        # 输出修改后的JSON文件
                        # print(data)
                        with open(json_path, 'w', encoding='utf-8') as f:
                            json.dump(config_data,
                                      f,
                                      ensure_ascii=False,
                                      indent=4)
                    return {"done": "added"}
            return {"done": "nothing"}
        # 包含 ~ 为 用户
        elif "~" in str(orderID) and value:
            '''
            修改用户名称
            '''
            order_list = str(orderID).split("~")
            _id = order_list[0]
            print(_id, value)
            conn = sqlite3.connect('./data/users.db')
            cur = conn.cursor()
            try:
                value = int(value)
                if value in [0, 1, 2]:
                    cur.execute('UPDATE users SET allowed=? WHERE id=?',
                                (value, _id))
                else:
                    print("无效权限")
            except Exception as e:
                print(e)
                cur.execute('UPDATE users SET username=? WHERE id=?',
                            (value, _id))
            conn.commit()
            conn.close()
        elif "!" in str(orderID) and value:
            '''
            修改ip对应备注
            '''
            order_list = str(orderID).split("!")
            _id = order_list[0]
            print('修改ip对应备注', _id, value)
            conn = sqlite3.connect('./data/users.db')
            cur = conn.cursor()
            cur.execute('''UPDATE ip SET address=? WHERE id=?''', (value, _id))
            conn.commit()
            conn.close()
        elif orderID and value == "@":
            '''
            物联网用
            '''
            async with aiofiles.open('./config/config.json',
                                     'r',
                                     encoding="utf8") as f:
                mqtt_name = ''.join(lazy_pinyin(str(orderID)))
                temp = json.loads(await f.read())
                log_path = temp[mqtt_name]
                if mqtt_name:
                    async with aiofiles.open(log_path,
                                             'r',
                                             encoding='gbk',
                                             errors='ignore') as f:
                        result = await f.readlines()
                        result = result[-50:]
            return {"mqttlog": result}

    return {"openid": orderID}


@app.post('/user')
async def user_post(data: dict = Body(...)):
    '''
    普通用户权限
    '''
    result = "done"
    if data:
        userID = data.get("id", "")
        userName = data.get("user", "")
        order = data.get("order", "")
        if order:
            if order == "update":
                if userID and userName:
                    # 更新用户信息
                    editUserName(int(userID), userName)
                    # th = Thread(target=editUserName, args=(int(userID), userName))
                    # th.daemon = True
                    # th.start()
                    result = userName
            elif order == "get" and userID:
                result = getRealnameByopenid(userID)
            return {"respdata": result}
    else:
        return {"error": "No JSON data received"}, 400


@app.post('/check')
async def check_post(data: dict = Body(...)):
    if data:
        openid = data.get("openid")
        version = data.get("version")
        th = Thread(target=updateUser, args=(
            openid,
            version,
        ))
        th.daemon = True
        th.start()
        return {"respdata": getRealnameByopenid(openid)}
    return {"error": "No JSON data received"}, 400


@app.get('/check')
async def check_get():
    async with aiofiles.open('./data/check.txt', 'r', encoding='utf8') as f:
        check_result = await f.read()
    return check_result


@app.get('/diancan')
async def diancan_get(n: str, d: str, t: int):
    '''
    利用点餐群 获取夜班信息
    '''
    d_time = int(time.time())
    # 本机微信保存
    if n and d and not t:
        '''
        保存点餐信息
        '''
        d = str(d).replace("歺", "餐").replace(" ", "")
        conn = sqlite3.connect('./data/diancan.db')
        c = conn.cursor()
        c.execute('''INSERT INTO diancan (name,diancan,time) VALUES (?,?,?)''',
                  (n, d, d_time))
        conn.commit()
        conn.close()
        return {"respdata": "success"}
    # 虚拟机记录保存
    elif d and t and not n:
        if not "人" in d and not "不" in d:
            conn = sqlite3.connect('./data/diancan.db')
            cur = conn.cursor()
            cur.execute(
                '''INSERT INTO weixinrecord (content,timestamp) VALUES (?,?)''',
                (d, t))
            conn.commit()
            conn.close()
            return {"respdata": "success"}
    else:
        return {"respdata": "error"}


@app.post('/diancan')
async def diancan_post(data: dict = Body(...)):
    if not data:
        return {"error": "No JSON data received"}, 400
    name = data.get('name')
    order = data.get('order')
    if name:
        '''
        读取点餐信息
        '''
        if order == 0:
            return {"respdata": diancan.yeban()}
        elif order == 1:
            return {"respdata": diancan.currentDay()}
        elif order == 2:
            # 时间范围通过点餐查询值班人员
            start = data.get('start')
            end = data.get('end')
            return {"respdata": diancan.currentDay(start, end)}
        elif order == 3:
            start = data.get('start')
            end = data.get('end')
            return {"respdata": diancan.currentDay(start, end)[1]}
        elif order == 4:
            # nick_name = data.get("nickname")
            # if nick_name:
            return {
                "respdata":
                str(
                    diancan.getCountByRealname(
                        diancan.getRealnameByNickname(name)))
            }
        elif order == 5:
            start = data.get('start')
            end = data.get('end')
            return {"respdata": diancan.checkWxRecord(start, end)}
        else:
            return {"respdata": []}


@app.post('/sumdc')
async def sumdc(i: str):
    '''
    获取点餐统计
    '''

    return {"respdata": sumdc(i)}


@app.get('/qq')
async def qq(i: str):
    '''
    QQ用的函数
    '''
    comID = i
    if comID:
        async with aiofiles.open('./config/config.json', 'r',
                                 encoding='utf8') as f:
            j = json.loads(await f.read())
            allowed_ids = j['allowed_ids']
        for allowed_id in allowed_ids:
            if comID == allowed_id['id']:
                result = []
                conn = sqlite3.connect(db2_path)
                cursor = conn.cursor()
                sql = "SELECT sysw,sqsw,time FROM qzcs order by time desc limit 1"
                cursor.execute(sql)
                result.append(cursor.fetchone())
                conn.close()
                conn = sqlite3.connect(r'D:\lljdata\swdb.db')
                cursor = conn.cursor()
                sql = 'SELECT sysw,xysw,time FROM swdb WHERE name="刘老涧抽水二站" order by time desc limit 1'
                cursor.execute(sql)
                result.append(cursor.fetchone())
                conn.close()
                if result:
                    return {"respdata": result}
                else:
                    return {"respdata": "error"}
        return {"respdata": "fobbiden"}, 403


# 报警大于warning_time_flag秒再保存
warning_time_flag = 60
warning_time = int(time.time())


@app.get('/warning')
async def warning_get(n: str, a: str):
    '''
    获取报警信息,存入warning.db
    '''
    return {"respdata": "no parameter"}, 400
    global warning_time
    global publish_flag
    global publish_name
    global publish_type

    publish_name = n
    publish_type = a
    now_time = int(time.time())
    if publish_name:
        publish_flag = True
        print(publish_name, publish_type)
        if (now_time - warning_time > warning_time_flag):
            # print(publish_name, a_type)
            warning_time = int(time.time())
            conn = sqlite3.connect('./data/warning.db')
            cur = conn.cursor()
            sqltxt = '''INSERT INTO warning(station,time,msg) VALUES(?,?,?)'''
            cur.execute(sqltxt, (publish_name, int(time.time()), publish_type))
            conn.commit()
            conn.close()
        return {"respdata": publish_name}
    else:
        return {"respdata": "no parameter"}, 400


@app.post('/warning')
async def warning_post(data: dict = Body(...)):
    # publish_flag = True
    # publish_type = 'test'
    if not data:
        return {"respdata": "No JSON data received"}, 400
    station = data.get('station')
    # print(type(station), station)
    if station is not None:
        if station == 1:
            station = 's1gate'
        elif station == 2:
            station = 's2gate'
        else:
            station = 'test'
        # print(station)
        conn = sqlite3.connect('./data/warning.db')
        cur = conn.cursor()
        now_time = int(time.time())
        timestamp_0 = time_to_timestamp(hour=0)
        timestamp_9 = time_to_timestamp(hour=9)
        timestamp_16 = time_to_timestamp(hour=16)
        timestamp_before_16 = time_to_timestamp(hour=16, step=-1)
        if now_time > timestamp_16:
            '''
                当前时间超过16点
                '''
            sqltxt = '''SELECT time FROM warning WHERE station=? AND time>?'''
            rf = conn.execute(sqltxt, (station, timestamp_16))
        elif now_time <= timestamp_16 and now_time >= timestamp_9:
            '''
                当前时间在9点-16点
                '''
            sqltxt = '''SELECT time FROM warning WHERE station=? AND time>?'''
            rf = conn.execute(sqltxt, (station, timestamp_0))
            # return jsonify({"respdata": "outtime"})
        elif now_time < timestamp_9 and now_time > timestamp_before_16:
            '''
                当前时间在前一天16点-今天9点
                '''
            sqltxt = '''SELECT time FROM warning WHERE station=? AND time>? AND time<?'''
            rf = conn.execute(sqltxt,
                              (station, timestamp_before_16, timestamp_9))
        if rf:
            return {"respdata": str(rf.fetchall())}
        else:
            return {"respdata": "error"}
    else:
        return {"respdata": "no parameter"}


@app.post('/upload')
async def upload(user: str = Form(...),
                 order: str = Form(...),
                 file: UploadFile = File(...)):
    '''
    图片识别接口
    '''
    '''
    获取用户openid
    '''
    # if name == 'file':
    print('调用拍照：', user)
    start_time = time.time()
    filepath = f'./wximage/{user}'
    if order:
        # 尝试保存文件
        try:
            if int(order) == 0:
                filepath += '/image/'
                if not os.path.exists(filepath):
                    os.makedirs(filepath)
                filepath += time.strftime(
                    '%Y-%m-%d %H%M%S', time.localtime(
                        time.time())) + os.path.splitext(file.filename)[-1]
                async with aiofiles.open(filepath, "wb") as buffer:
                    await buffer.write(await file.read())
                return {"respdata": "ok"}
                # ocrtext, imgbase64 = ocr(filepath, user)
                # # print(ocrtext)
                # # print(imgbase64)
                # return {
                #     "respdata": [ocrtext, str(imgbase64)],
                # }
            elif int(order) == 1:
                filepath += '/fapiao/'
                if not os.path.exists(filepath):
                    os.makedirs(filepath)
                filepath += time.strftime(
                    '%Y-%m-%d %H%M%S', time.localtime(
                        time.time())) + os.path.splitext(file.filename)[-1]
                # file_buffer = await file.read()
                async with aiofiles.open(filepath, "wb") as buffer:
                    await buffer.write(await file.read())
                result = scan_qrcode(filepath)
                if result:
                    print(result)
                    saved_value, fapiao_data = save(result[0]['data'], user)
                    if not saved_value:
                        os.remove(filepath)
                    else:
                        th = Thread(target=updateFapiaoDetail,
                                    args=(
                                        result[0]['data'],
                                        user,
                                        filepath,
                                    ),
                                    daemon=True)
                        th.start()

                    return {
                        "respdata": result[0]['data'],
                        "save": saved_value,
                        "detail": fapiao_data
                    }
                else:
                    os.remove(filepath)
                return {"respdata": False}
            elif int(order) == 2:
                pass
        except Exception as e:
            print(e)
            # 处理保存文件时可能出现的异常
            return {
                "respdata": "Error occurred while saving the file.",
                "error": str(e)
            }, 500
        finally:
            print("用时:", time.time() - start_time, "秒")
    else:
        return {"respdata": "fobbiden"}, 403


@app.post('/file')
async def file(user: str = Form(...),
               tag: str = Form(...),
               file: UploadFile = File(...)):
    '''
    上传普通文件接口
    '''
    if user and tag and file:
        dir_name = time.strftime("%Y%m%d%H", time.localtime(time.time()))
        filepath = f'./file/{tag}/{user}/{dir_name}'
        if not os.path.exists(filepath):
            os.makedirs(filepath)
        file_content = await file.read()
        filepath += f'/{file.filename}'
        async with aiofiles.open(filepath, "wb") as buffer:
            await buffer.write(file_content)
            return {"respdata": f"{len(file_content)}"}
    else:
        return {"respdata": "no parameter"}, 400


@app.get('/camera')
async def camera_get(tag: str, t: int):
    '''
    获取摄像头图片
    '''
    if tag:
        if tag == 'get':
            return {"respdata": get_camera()}
        tag = tag.replace('号', '#').replace('_zk', '\d+_zk')
        camera_name = tag.rsplit('_', 1)[-1]
        img_bytes = get_camera_path(camera_name=camera_name, camera_time=t)
        if img_bytes:
            return Response(img_bytes, media_type="image/jpeg")
        return {"respdata": "no file"}, 404


@app.post('/camera')
async def camera_post(cameraName: dict):
    '''
    上传摄像头图片
    '''
    if cameraName:
        '''
        '''
        print(cameraName)
        conn = sqlite3.connect(camera_path)
        cur = conn.cursor()
        cur.execute(
            f"SELECT time FROM camera1 WHERE name='{cameraName['cameraName']}' ORDER  BY time DESC LIMIT 100"
        )
        records = cur.fetchall()
        if records:
            records = [record[0] for record in records]
        return {"respdata": records}
    return {"respdata": "no parameter"}, 400


@app.get('/swpic')
async def swpic(tag: str):
    '''
    获取水位图片
    '''
    if tag:
        # print(tag)
        try:
            imgdata = requests.get(
                f'http://www.jsswj.com.cn:88/jsswxxSSI/static/map1/0/3/{tag}.png?t={int(time.time())}',
                timeout=1)
            return Response(imgdata.content, media_type="image/png")
        except Exception as e:
            print(f"Error fetching image: {e}")
            # return {"respdata": "no file"}, 404
            async with aiofiles.open(r'.\image\com_error.png', 'rb') as img:
                return Response(await img.read(), media_type="image/png")
    return {"respdata": "no parameter"}, 400


@app.post('/swpic')
async def swpic_post(data: dict = Body(...)):
    '''
    获取水位图片
    '''
    if data:
        user = data.get('user')
        order = data.get('order')
        if user and order:
            if order == 'getgllist':
                try:
                    async with aiofiles.open('./config/setting.json',
                                             'r',
                                             encoding='utf8') as f:
                        settings = json.loads(await f.read())
                        gllist = settings['gllist']
                    return {"respdata": f'{gllist}'}
                except Exception as e:
                    print(f"Error {e}")
                    return {"respdata": "error"}, 500
    return {"respdata": "no parameter"}, 400


@app.get('/dc')
async def dc_get(tag: str, request: Request):
    '''
    点餐统计
    '''
    if tag == 'llj':
        return templates.TemplateResponse("diancan.html", {
            "request": request,
            "title": tag
        })
        # return {"respdata": "ok"}, 200
    return {"respdata": "no parameter"}, 400


@app.post('/dc')
async def dc_post(data: dict = Body(...)):
    '''
    '''

    if data:
        start = data["startTimestamp"] // 1000
        end = data["endTimestamp"] // 1000
        print(start, end)
        return {"respdata": diancan.tongji(start, end)}
    return {"respdata": None}


@app.post('/fapiao')
async def fapiao_post(data: dict = Body(...)):
    '''
    发票信息查询
    '''
    if data:
        user = data["name"]
        order = data["order"]
        print(user, order)
        order_list = str(order).split('&')
        result = "ok"
        if order_list[0] == '0':
            start_time = order_list[1]
            end_time = order_list[2]
            result = getFapiaoByTime(start_time=int(start_time) / 1000,
                                     end_time=int(end_time) / 1000)
            # return {"respdata": result}
        elif order_list[0] == '1':
            result = getFapiaoByName(name=order_list[1])
        elif order_list[0] == '2':
            result = getFapiaoByStatus(user)
        elif order_list[0] == 'multi':
            result = str(getFapiaoWithOthers())
        elif order_list[0] == 'names':
            result = getAllnames()
        elif order_list[0] == 'sub':
            res = data['res']
            if res:
                print(res)
                result = wechatsubscribe.update_user_template_id(user, res)
        elif order_list[0] == 'info':
            data = user
            result = getFapiaoInfoByData(data=data)
        elif order_list[0] == 'check':
            data = user
            result = check_fapiao_Expired(openid=user, days=15)
        return {"respdata": result}
    return {"respdata": None}, 400


@app.get('/wxsq')
async def wxsq_get():
    '''
    读取微信水情群调度内容
    这个从其他电脑读来的水情信息，目前还没启用2025年8月10日
    '''
    async with aiofiles.open("./config/config.json", 'r',
                             encoding='utf8') as f:
        weixin_lysq_json = json.loads(await f.read())
        weixin_lysq_path = weixin_lysq_json['weixin_lysq']
    async with aiofiles.open(weixin_lysq_path, 'r', encoding='utf8') as f:
        weixin_lysq = await f.read()
        return {"respdata": weixin_lysq}


@app.post('/location')
async def location_post(data: dict = Body(...)):
    '''
    统计用户位置信息
    '''
    if data:
        # openid
        user = data.get('user', None)
        lat = data.get('lat', None)
        lon = data.get('lon', None)
        if user and lat and lon:
            conn = sqlite3.connect('./data/users.db')
            cur = conn.cursor()
            user_id = cur.execute("SELECT id FROM users WHERE openid=?",
                                  (user, )).fetchone()
            if user_id:
                user_id = user_id[0]
                cur.execute(
                    '''SELECT lat,lon FROM location WHERE userid=? ORDER BY time DESC''',
                    (user_id, ))
                existing_location = cur.fetchone()
                if existing_location:
                    existing_lat, existing_lon = existing_location
                    if existing_lat == lat and existing_lon == lon:
                        cur.execute(
                            '''UPDATE location SET time=? WHERE userid=? AND lat=? AND lon=?''',
                            (int(time.time()), user_id, lat, lon))
                    else:
                        cur.execute(
                            '''INSERT INTO location (userid,lat,lon,time) VALUES (?,?,?,?)''',
                            (user_id, lat, lon, int(time.time())))
                else:
                    cur.execute(
                        '''INSERT INTO location (userid,lat,lon,time) VALUES (?,?,?,?)''',
                        (user_id, lat, lon, int(time.time())))
                conn.commit()
                conn.close()
                return {"respdata": "success"}
            else:
                conn.close()
                return {"respdata": "user not found"}, 404


@app.get('/location')
async def location_get(userid: str):
    if userid:
        conn = sqlite3.connect('./data/users.db')
        cur = conn.cursor()
        try:
            cur.execute(
                "SELECT lat,lon,time FROM location WHERE userid=? ORDER BY time DESC LIMIT 10;",
                (userid, ))
            res = cur.fetchall()
            if res:
                return {"respdata": res}
        except Exception as e:
            print(e)
        finally:
            conn.close()
        # return get_location(userid)


@app.get('/frame')
async def frame_get(id: str):
    '''
    转发视频流
    '''
    if id:
        if int(id) == 0:
            id = 2
        return FileResponse(f'data/onecloud/temp_{id}.jpg',
                            media_type='image/jpg')
    else:
        return {"respdata": "no parameter"}, 400


@app.get('/sqnotice')
async def sqnotice_get(text: str):
    '''
    水情滚动通知保存
    '''
    if text:
        print(text)
        async with aiofiles.open('./data/miniindex/首页调令.txt',
                                 'w',
                                 encoding='utf8') as f:
            await f.write(text)
        savewarning.save_notice_to_db("调度", text, "首页调令", True)
        return {"respdata": "success"}, 200
    else:
        return {"respdata": "no parameter"}, 400


@app.get('/backgroundimg')
async def backgroundimg_get():
    '''
    获取首页背景图片
    '''
    return FileResponse('./data/miniindex/sq.png', media_type='image/png')


@app.get('/mainnotice')
async def mainnotice_get():
    '''
    主页滚动通知获取
    '''
    # 获取目录下所有文件路径
    miniindex_list = []
    for root, dirs, files in os.walk('./data/miniindex/'):
        for file in files:
            if not file.endswith('.txt'): continue
            async with aiofiles.open(os.path.join(root, file),
                                     'r',
                                     encoding='utf8') as f:
                miniindex_list.append(await f.readline())
    return {"respdata": str(miniindex_list) if miniindex_list else "no notice"}
    # print(miniindex_list)


@app.get("/sw")
async def sw_get():
    '''
    获取最新水位值
    '''
    gc_list = ["刘老涧抽水站", "刘老涧抽水二站", "皂河抽水站", "皂河二站", "泗阳抽水一站", "泗阳抽水二站"]
    sw_list = []
    for gc in gc_list:
        sw_list.append(getsw_sw(name=gc))
    return {"respdata": sw_list}


@app.post('/control')
async def control_post(data: dict):
    '''
    控制
    '''
    if data:

        openid = data.get("user")
        order = data.get("order")
        if openid in admin_openid:
            if order == 0:
                import subprocess
                try:
                    subprocess.run([
                        "netsh", "interface", "set", "interface", "以太网",
                        "enabled"
                    ],
                                   check=True,
                                   stdout=subprocess.DEVNULL,
                                   stderr=subprocess.DEVNULL)
                    return {"respdata": "ok"}
                except Exception as e:
                    print(e)
                    return {"respdata": str(e)}


@app.post('/jssqapp')
async def jssqapp_post(data: dict):
    '''
    获取江苏水情app数据
    '''
    # from jssqapp import getAppData
    if data:
        openid = data.get("user")
        order = data.get("order")
        if order == 0:
            async with aiofiles.open('./data/jssqapp2.json',
                                     'r',
                                     encoding='utf8') as f:
                jssqapp_content = json.loads(await f.read())
            return {"respdata": jssqapp_content}
    return {"respdata": "ok"}


@app.post('/tongji')
async def tongji_post(data: dict):
    '''
    获取统计
    '''
    print(data)
    import tongji
    if data:
        openid = data.get("user", '')
        order = data.get("order", '')
        _type = data.get('type', '')
        start_timestamp = data.get('start')
        end_timestamp = data.get('end')
        if order == "sum":
            if _type == "daily":
                return {
                    "respdata":
                    tongji.tongji_all_jz_hours(start_timestamp, end_timestamp,
                                               'daily')
                }
            elif _type == "monthly":
                return {
                    "respdata":
                    tongji.tongji_all_jz_hours(start_timestamp, end_timestamp,
                                               'monthly')
                }
            elif _type == "yearly":
                return {
                    "respdata":
                    tongji.tongji_all_jz_hours(start_timestamp, end_timestamp,
                                               'yearly')
                }
        elif order == "watergrass":
            return {"respdata": tongji.get_watergrass(int(_type))}
        return {"respdata": "no parameter"}, 400


LEBELIMGPATH = r'D:\results\labelimg'
TARGETPATH = r'D:\myGitee\yolo-universal-training\my_dataset'


@app.get('/labelimg')
async def labelimg_get(request: Request, imgname: str):
    '''
    获取标注页面'''
    print(imgname)
    if not imgname:
        return templates.TemplateResponse("labelimg.html", {
            "request": request,
            "title": "标注"
        })
    else:
        return FileResponse(fr'{LEBELIMGPATH}\{imgname}',
                            media_type='image/jpg')


@app.get('/labeltxt')
async def labeltxt_get(labelname: str):
    '''
    获取标注文本
    '''
    print(labelname)
    if labelname:
        return FileResponse(fr'{LEBELIMGPATH}\{labelname}',
                            media_type='text/plain')
    return {"respdata": "no parameter"}, 400


@app.post('/labeltxt')
async def labeltxt_post(data: dict):
    '''
    保存标注文本
    '''
    if data:
        labelname = data.get("labelname", "")
        labeltxt = data.get("labeltxt", '')
        if labelname and labeltxt:
            if labeltxt == 'DEL':
                try:
                    os.remove(fr'{LEBELIMGPATH}\{labelname}')
                    # 删除对应的jpg文件
                    jpg_filename = labelname.replace('.txt', '.jpg')
                    jpg_filepath = fr'{LEBELIMGPATH}\{jpg_filename}'
                    if os.path.exists(jpg_filepath):
                        os.remove(jpg_filepath)
                    return {"respdata": "deleted"}
                except Exception as e:
                    print(e)
                    return {"respdata": f"{e}"}, 500
            elif labeltxt == 'MOVE':
                try:
                    # os.rename(fr'{LEBELIMGPATH}\{labelname}',
                    #          fr'{TARGETPATH}\labels\{labelname}')
                    shutil.move(fr'{LEBELIMGPATH}\{labelname}',
                                fr'{TARGETPATH}\labels\{labelname}')
                    jpg_filename = labelname.replace('.txt', '.jpg')
                    jpg_filepath = fr'{LEBELIMGPATH}\{jpg_filename}'
                    # os.rename(jpg_filepath,
                    #          fr'{TARGETPATH}\images\{jpg_filename}')
                    shutil.move(jpg_filepath,
                                fr'{TARGETPATH}\images\{jpg_filename}')
                    return {"respdata": "moved"}
                except Exception as e:
                    print(e)
                    return {"respdata": "error"}, 500
            elif labeltxt == 'CHECK':
                try:
                    '''
                    获取触发训练剩余数量
                    '''
                except Exception as e:
                    return {"respdata": str(e)}, 500
            elif labeltxt == 'DELALL':
                '''
                清空文件夹 LEBELIMGPATH
                '''
                try:
                    filelist = os.listdir(LEBELIMGPATH)
                    for filename in filelist:
                        file_path = os.path.join(LEBELIMGPATH, filename)
                        if os.path.isfile(file_path):
                            os.remove(file_path)
                    return {"respdata": "all deleted"}
                except Exception as e:
                    print(e)
                    return {"respdata": str(e)}, 500
            else:
                async with aiofiles.open(fr'{LEBELIMGPATH}\{labelname}',
                                         'w') as f:
                    await f.write(labeltxt)
                    # print(labelname, labeltxt)
                    return {"respdata": "success"}


@app.post('/labelimg')
async def labelimg_post(data: dict):
    '''
    获取标注图片
    '''
    if data:
        imgname = data.get("imgname", "")
        if imgname:
            async with aiofiles.open(fr'{LEBELIMGPATH}\{imgname}') as img:
                return Response(await img.read(), media_type='image/jpg')
        else:
            # 返回文件夹{LEBELIMGPATH} 里所有jpg文件名
            filelist = os.listdir(LEBELIMGPATH)
            imglist = [img for img in filelist if img.endswith('.jpg')]
            labellist = [label for label in filelist if label.endswith('.txt')]
            # print(imglist)
            return {"imglist": imglist, "labellist": labellist}
            # return
    return "no parameter", 400


@app.get('/wgimg')
async def wgimg_get(t: str):
    '''
    获取水草照片
    '''
    if t:
        try:
            async with aiofiles.open(f'./data/miniindex/{t}.jpg', 'rb') as img:
                return Response(await img.read(), media_type='image/jpg')
            # elif _type == 'max':
            #     async with aiofiles.open('','rb') as img:
            #         return Response(await img.read(), media_type='image/jpeg')
        except Exception as e:
            print(e)
            return {"respdata": "no parameter"}, 400


@app.get('/modelinfo')
async def modelinfo_get():
    '''
    获取模型文件信息
    '''
    import os
    model_path = r'D:\myGitee\watergrassyolo\models\best.pt'
    if os.path.exists(model_path):
        # 获取文件修改时间
        mod_time = os.path.getmtime(model_path)
        # 转换为可读格式
        import time
        mod_time_str = time.strftime('%Y-%m-%d %H:%M:%S',
                                     time.localtime(mod_time))
        return {"respdata": {"modified_time": mod_time_str}}
    else:
        return {"respdata": "Model file not found"}, 404


@app.get('/detectimg')
async def detectimg_get(request: Request):
    '''
    调用yolo best.pt检测目标图片并返回标记框
    '''
    return templates.TemplateResponse('detectimg.html', {
        "request": request,
        "title": "检测测试"
    })


@app.post('/detectimg')
async def detectimg_post(image: UploadFile = File(...)):
    '''
    调用yolo best.pt检测目标图片并返回标记框
    '''
    # 直接读取上传的文件内容，不保存到temp.jpg
    content = await image.read()

    # 调用目标检测服务
    async with httpx.AsyncClient() as client:
        files = {"image": (image.filename, content, image.content_type)}
        response = await client.post("http://127.0.0.1:5005/detect",
                                     files=files)

    if response.status_code == 200:
        return {"boxes": response.json()}
    else:
        return {"error": "Detection failed"}


# 添加新路由：通过图片URL进行检测
@app.post('/detectimg_url')
async def detectimg_url_post(data: dict = Body(...)):
    '''
    通过图片URL调用yolo best.pt检测目标图片并返回标记框
    '''
    image_url = data.get('image_url')
    if not image_url:
        return {"error": "Missing image_url in request body"}

    try:
        # 下载图片内容

        async with httpx.AsyncClient() as client:
            response = await client.get(image_url)
            response.raise_for_status()
            image_content = response.content

        # 调用目标检测服务
        async with httpx.AsyncClient() as client:
            files = {"image": ("image.jpg", image_content, "image/jpeg")}
            detection_response = await client.post(
                "http://127.0.0.1:5005/detect", files=files)

        if detection_response.status_code == 200:
            return {"boxes": detection_response.json()}
        else:
            return {"error": "Detection failed"}
    except Exception as e:
        return {"error": f"Failed to process image: {str(e)}"}


@app.get('/ragflow')
async def ragflow_get(request: Request):
    '''
    接收ragflow的知识库文件
    '''
    return templates.TemplateResponse('uploadfiletoragflow.html', {
        "request": request,
        "title": "知识库"
    })


# ========== 配置参数 ==========
BASE_URL = "http://localhost:8880"  # 替换为你的 RAGFlow 地址
KB_ID = "e2b21daa930e11f0b08622b1f22ba2d3"  # 替换为你的知识库 ID
API_TOKEN = "ragflow-lkZGUwMmE2OTVlOTExZjA5NzY4ZmVhZD"  # 替换为你的 API Token
# FILE_PATH = "/path/to/your/document.pdf"  # 替换为你要上传的文件路径
headers = {"Authorization": f"Bearer {API_TOKEN}"}
from pathlib import Path


@app.post('/ragflow')
async def ragflow_post(file: UploadFile = File(...)):
    '''
    接收ragflow的知识库文件
    '''
    # 创建保存目录（如果不存在）
    save_directory = r"E:\LLM\ragflowfiles"
    os.makedirs(save_directory, exist_ok=True)

    # 构造文件保存路径
    file_path = os.path.join(save_directory, file.filename)

    # 保存上传的文件
    async with aiofiles.open(file_path, "wb") as buffer:
        content = await file.read()
        await buffer.write(content)
    # import requests
    file = Path(file_path)
    # 使用 httpx.AsyncClient 发起异步请求
    async with httpx.AsyncClient(timeout=30.0) as client:
        try:
            with open(file, 'rb') as f:
                files = {
                    'file': (file.name, f)  # 可根据文件类型调整 MIME
                }
                data = {
                    'parser_type': 'auto'  # 自动解析，或指定如 'pdf', 'txt' 等
                }

                # 上传文件并触发解析（假设上传接口自动触发解析）
                response = await client.post(
                    f"{BASE_URL}/api/v1/datasets/{KB_ID}/documents",
                    headers=headers,
                    data=data,
                    files=files)

            # 检查响应
            if response.status_code == 200 or response.status_code == 201:
                result = response.json()
                doc_id = result.get("data",
                                    {})[0].get("id") or result.get("id")
                print(f"✅ 文件上传成功！文档 ID: {doc_id}")
                document_ids = []
                document_ids.append(doc_id)
                data = {"document_ids": document_ids}
                response = await client.post(
                    f"{BASE_URL}/api/v1/datasets/{KB_ID}/chunks",
                    headers=headers,
                    json=data)
                if response.status_code == 200 or response.status_code == 201:
                    result = response.json()
                    print(result)
                # 修改返回格式，确保返回有效的JSON响应
                return JSONResponse(
                    content={
                        "status": "success",
                        "message": "文件上传并解析成功",
                        "document_id": doc_id
                    })
            else:
                print(f"❌ 上传失败，状态码: {response.status_code}")
                print(f"响应内容: {response.text}")
                # 修改返回格式，确保返回有效的JSON响应
                return JSONResponse(content={
                    "status": "error",
                    "message": f"上传失败，状态码: {response.status_code}",
                    "details": response.text
                },
                                    status_code=response.status_code)

        except Exception as e:
            print(f"❌ 请求异常: {e}")
            # 修改返回格式，确保返回有效的JSON响应
            return JSONResponse(content={
                "status": "error",
                "message": f"请求异常: {str(e)}"
            },
                                status_code=500)


@app.get('/webstream')
async def webstream_get(request: Request):
    '''
    接收摄像头图片
    '''
    return templates.TemplateResponse('webstream.html', {
        "request": request,
        "title": "摄像头"
    })


@app.post('/webstream')
async def webstream_post(request: Request):
    '''
    识别图片中文字，返回box和文字内容
    '''
    try:
        # 获取JSON数据
        data = await request.json()
        image_data = data.get('image')
        selectType = data.get('type', None)
        if not image_data:
            return {"error": "No image data received"}

        # 移除base64头部（如data:image/jpeg;base64,）
        if image_data.startswith('data:image'):
            image_data = image_data.split(',')[1]

        # 解码base64数据
        image_bytes = base64.b64decode(image_data)
        ocr_result = ocrimagebytes(image_bytes, "临时")
        print(ocr_result[0])
        if ocr_result[0] and selectType:
            if ocr_result[0][0]:
                input_text = ''.join(ocr_result[0][0])
                result = xxtk.main(input_text, selectType)
                # 返回OCR结果，包括识别的文字和图像base64
                return {"result": result}
        return {"error": '无'}

    except Exception as e:
        print(e)
        return {"error": str(e)}


@app.get('/p')
async def p_get(request: Request):
    '''
    工控预览
    '''
    return templates.TemplateResponse('zhongkong.html', {
        "request": request,
        "title": "中控"
    })


@app.get('/gc')
async def gc_get(id: str = '0'):
    '''
    工控预览
    '''
    if id:
        try:
            # 读取图片文件并返回Response对象，避免Content-Length不匹配问题
            with open(f'D:/myGitee/control-net/data/onecloud/temp_{id}.jpg', 'rb') as f:
                image_data = f.read()
            return Response(content=image_data, media_type='image/jpeg')
        except Exception as e:
            return {"error": str(e)}


if __name__ == "__main__":
    from mqttser import mqtt_run
    th1 = Thread(target=mqtt_run,
                 args=('服务器', [("software", 0), ("s1gate", 0), ("s2gate", 0)]),
                 daemon=True)
    th1.start()

    # th3 = Thread(target=check_cpu_memory, args=(process, ), daemon=True)
    # th3.start()
    import uvicorn
    uvicorn.run(app="llj_ser_fastapi:app", host='0.0.0.0', port=5000)
    # '''
    # print("\033[0;31;42m这是默认红色字体背景绿色\033[0m")
    # print("\033[1;32;43m这是高亮绿色字体背景黄色\033[0m")
    # print("\033[4;33;45m这是下划线黄色字体背景紫红色\033[0m")
    # print("\033[5;34;46m这是闪烁蓝色字体背景青蓝色\033[0m")
    # '''
